const db = require('../db')
const setting = require('./setting')
const _ = require('lodash')
const House = require('models/House')
const pagify = require('utils/pagify')
const RangeParser = require('utils/RangeParser')

const processHouseWithType = (type) => {
  return function (house) {
    return processHouse(house, type)
  }
}
const processHouse = (house, type) => {
  if (!house) { return }
  _.each(['usage', 'facility'], (key) => {
    house[key] = house[key] ? house[key].split(',') : []
  })
  try {
    house.pics = house.pics ? JSON.parse(house.pics) : []
  } catch (e) {
    house.pics = house.pics ? house.pics.split(',').map((pic) => {
      return {
        title: '',
        url: pic
      }
    }) : []
  }

  house.desc = house.desc && house.desc.replace(/\u2028/g,'')

  type = type || house.type
  if (type == 1) {
    house.priceText = house.monthPrice ? ('¥' + house.monthPrice + '/月') : '待定'
  } else {
    const priceTextArr = []
    if (house.dayEnabled && house.dayPrice) {
      priceTextArr.push('¥' + house.dayPrice + '/天')
    } else if (house.hourEnabled && house.hourPrice) {
      priceTextArr.push('¥' + house.hourPrice + '/小时') 
    }
    house.priceText = priceTextArr.length ? priceTextArr.join(' ') : '待定'
  }

  return house
}

const calMonthPrice = (house) => {
  if (house.type == 2) {
    if (house.dayEnabled && house.dayPrice) {
      house.monthPrice = house.dayPrice * 30
    } else if (house.hourEnabled && house.hourPrice) {
      house.monthPrice = house.hourPrice * 720
    }
  }
}

const updateSearchIndex = async (house) => {
  if (house.capacity) {
    let capacityOptions = await setting.get('CapacityOptions')
    house.capacityRange = new RangeParser(capacityOptions).range(house.capacity)
  }

  if (house.area) {
    let areaOptions = await setting.get('AreaRangeOptions')
    house.areaRange = new RangeParser(areaOptions).range(house.area)
  }

  if (house.monthPrice) {
    let priceOptions = await setting.get('MonthPriceRangeOptions')
    house.monthPriceRange = new RangeParser(priceOptions).range(house.monthPrice)
  }

  if (house.dayPrice) {
    let priceOptions = await setting.get('DayPriceRangeOptions')
    house.dayPriceRange = new RangeParser(priceOptions).range(house.dayPrice)
  }

  if (house.type.hourPrice) {
    let priceOptions = await setting.get('HourPriceRangeOptions')
    house.hourPriceRange = new RangeParser(priceOptions).range(house.hourPrice)
  }
}

/**
 * 清理异常值
 * @param {House} house 
 */
const sanitizeHouse = (house) => {
  for (key in house) {
    if (!house[key]) {
      delete house[key]
    }
  }
  if (house.type == 1) {
    house.dayEnabled = 0
    house.hourEnabled = 0
    house.yearEnabled = house.yearEnabled ? +house.yearEnabled : 0
    house.monthEnabled = house.monthEnabled ? +house.monthEnabled : 0
    house.dayPrice = null
    house.hourPrice = null
  } else if (house.type == 2) {
    house.yearEnabled = 0
    house.monthEnabled = 0
    house.dayEnabled = house.dayEnabled ? +house.dayEnabled : 0
    house.hourEnabled = house.hourEnabled ? +house.hourEnabled : 0
    house.monthPrice = null
  }
  if (!house.hourEnabled) {
    house.openHour = null
    house.closeHour = null
  } else if (house.closeHour < house.openHour) {
    throw new Error('关闭时间必须晚于开始时间')
  }
}

/**
 * @param  {Object} house
 * @return {Number} id
 */
const create = async (house) => {
  const {
    name,
    type
  } = house

  if (!name) {
    throw new Error('name is empty')
  }

  if (!type) {
    throw new Error('type is empty')
  }

  for (key in house) {
    if (!house[key]) {
      delete house[key]
    }
  }

  house.addTime = new Date()
  house.updateTime = new Date()
  house.status = 0
  sanitizeHouse(house)
  calMonthPrice(house)
  await updateSearchIndex(house)
  const result = await db('House')
    .returning('id')
    .insert(house)
  return result[0]
}

const update = async (id, house) => {
  const {
    name
  } = house

  if (name === '') {
    throw new Error('name is empty')
  }

  sanitizeHouse(house)

  delete house.addTime
  house.updateTime = new Date()
  calMonthPrice(house)
  await updateSearchIndex(house)

  const result = await db('House')
    .where('id', '=', id)
    .update(house)

  return result
}

/**
 * 更新图片结构为新结构
 */
const updateImageStructure = async () => {
  let houses = await House.query(function (qb) {
    qb.where({ status: 0 })
  }).fetchAll()

  houses = houses.toJSON()
  for (let i = 0; i < houses.length; i++) {
    let house = houses[i]
    if (house.pics.length && typeof house.pics[0] === 'string') {
      let pics = JSON.stringify(house.pics.map((pic) => {
        return {
          title: '',
          url: pic
        }
      }))
      await House.where({
        id: house.id
      }).save({
        pics: pics
      }, {
        patch: true
      })
    }
  }
}

/**
 * @param  {Number} id
 * @return {Object} status
 */
const remove = async (id) => {
  const result = await db('House')
    .update({
      status: 1,
      updateTime: new Date()
    })
    .where('id', '=', id)
  return true
}

/**
 * @param {Number} type 类型 1: 年月 2: 日时
 * @param {Number} priceRange 价格区间
 * @param {Number} houseType 房型
 * @param {Number} capacity 人数
 * @param {Number} scenic 景点
 */
const query = async ({name, yearEnabled, monthEnabled, dayEnabled, hourEnabled, type, areaRange, priceRange, houseType, capacityRange, scenic, hourPriceRange, dayPriceRange, monthPriceRange, orderByPrice}, page = 1, pageSize = 10) => {
  page = +page
  const query = db('House')
  if (name) {
    query.where('name', 'like', '%' + name + '%')
  }

  if (type) {
    query.where(function () {
      let q = this
      type.split(',').forEach((type, i) => {
        q[i == 0 ? 'where' : 'orWhere']('type', type)
      })
    })
  }
  if (yearEnabled) {
    query.where('yearEnabled', '=', 1)
  }
  if (monthEnabled) {
    query.where('monthEnabled', '=', 1)
  }
  if (dayEnabled) {
    query.where('dayEnabled', '=', 1)
  }
  if (hourEnabled) {
    query.where('hourEnabled', '=', 1)
  }
  if (priceRange) {
    query.where('priceRange', '=', priceRange)
  }
  if (areaRange) {
    query.where('areaRange', '=', areaRange)
  }
  if (houseType) {
    query.where('houseType', '=', houseType)
  }
  if (capacityRange) {
    query.where('capacityRange', '=', capacityRange)
  }
  if (scenic) {
    query.where('scenic', '=', scenic)
  }

  if (hourPriceRange) {
    query.where('hourPriceRange', '=', hourPriceRange)
  }

  if (dayPriceRange) {
    query.where('dayPriceRange', '=', dayPriceRange)
  }

  if (monthPriceRange) {
    query.where('monthPriceRange', '=', monthPriceRange)
  }

  if (orderByPrice) {
    query.orderBy('monthPrice', orderByPrice == 1 ? 'asc' : 'desc')
  }
  
  query.where('status', '=', '0')
  let result = await pagify.knex(query, page, pageSize)
  let processFunc = house => processHouse(house)
  if (type) {
    if (type.indexOf('3') !== -1) {
      processFunc = processHouseWithType(3)
    } else if (type.indexOf('4') !== -1) {
      processFunc = processHouseWithType(4)
    }
  }
  result.data = result.data.map(processFunc)
  return result
}

const SELECTED_KEY = 'SelectedHouseIds'
const saveSelected = async (ids) => {
  if (!ids) {
    throw '缺少参数'
  }

  ids = ids.split(',').filter(item => /^\d+$/.test(item)).join(',')
  return await setting.set(SELECTED_KEY, ids)
}

const getSelected = async () => {
  let selectedResults = await setting.get(SELECTED_KEY)
  let ids = selectedResults ? selectedResults.split(',') : []
  let results = await db('House').where('id', 'in', ids).select()

  return ids.map((id) => {
    return processHouse(_.find(results, item => item.id === +id))
  })
}

const get = async (id) => {
  const results = await db('House').select().where('id', '=', id)
  return processHouse(results[0])
}

module.exports = {
  create,
  remove,
  update,
  query,
  get,
  getSelected,
  saveSelected,
  updateImageStructure
}